#include "dauproxyapi.h"
#include "errno_sdk.h"
#include <dlfcn.h>
#include <cstdio>   // 为 printf
#include <cstdlib>  // 为 getenv
#include <cstring>  // 为 strlen
#include <string>   // 为 std::string
#include <iostream> // 为 std::cout 和 std::endl
#define CHECK_DLERROR(errCode)  \
    do {                  \
        char *e = dlerror();                  \
        if ((e) != nullptr) { \
            std::printf("dl error: %s\n", (e)); \
            return (errCode);                  \
        }   \
    } while(0)

DauProxyApi::DauProxyApi()
{
    pHandle = nullptr;
}

DauProxyApi::~DauProxyApi()
{
    if (pHandle != nullptr)
    {
        std::printf("Execute ~DauProxyApi\n");
        dlclose(pHandle);
    }
}

DauProxyApi* DauProxyApi::GetInstance()
{
    static DauProxyApi g_dayProxyApi;
    return &g_dayProxyApi;
}

#define SET_FUNC(handle, pFunc, funcDef, name) \
    do {                                       \
             (pFunc) = (funcDef)dlsym((handle), (name)); \
             CHECK_DLERROR(ERR_LIB_DAUPROXY_NO_FUNC);    \
    }while(0)

int DauProxyApi::Init()
{
    char *libProxyPath = std::getenv("LIB_PROXY_PATH");
    if (libProxyPath == nullptr || std::strlen(libProxyPath) == 0)
    {
        return ERR_LIB_PROXY_PATH;
    }

    std::string soFilePath = std::string(libProxyPath);
    if (soFilePath.back() != '/')
    {
        soFilePath.append("/");
    }
    soFilePath.append("libdauServerProxyC.so");

    if (pHandle == nullptr)
    {
        pHandle = dlopen(soFilePath.c_str(), RTLD_LAZY | RTLD_LOCAL);
        CHECK_DLERROR(ERR_LIB_DAUPROXY);
    }

    SET_FUNC(pHandle, ProxySetLibraryPath, dauproxy_api_func::ProxySetLibraryPath, "Proxy_S_SetLibraryPath");
    int code = ProxySetLibraryPath(libProxyPath);
    if (code < 0)
    {
        return ERR_CALL_PROXY_SETLIBRARYPATH;
    }

    SET_FUNC(pHandle, ProxyInitLibrary, dauproxy_api_func::ProxyInitLibrary, "Proxy_S_Init_Library");
    code = ProxyInitLibrary();
    if (code < 0)
    {
        return ERR_CALL_PROXY_INITLIBRARY;
    }

    SET_FUNC(pHandle, ProxyReleaseLibrary, dauproxy_api_func::ProxyReleaseLibrary, "Proxy_S_Release_Library");
    SET_FUNC(pHandle, ProxyCreateDevice, dauproxy_api_func::ProxyCreateDevice, "Proxy_S_CreateDevice");
    SET_FUNC(pHandle, ProxyAddDeviceChannelInfoPlus, dauproxy_api_func::ProxyAddDeviceChannelInfoPlus, "Proxy_S_AddDeviceChannelInfoPlus");
    SET_FUNC(pHandle, ProxyDelDeviceChannelInfo, dauproxy_api_func::ProxyDelDeviceChannelInfo, "Proxy_S_DelDeviceChannelInfo");
    SET_FUNC(pHandle, ProxySetChannelMediaInfo, dauproxy_api_func::ProxySetChannelMediaInfo, "Proxy_S_SetChannelMediaInfo");
    SET_FUNC(pHandle, ProxyStartServer, dauproxy_api_func::ProxyStartServer, "Proxy_S_StartServer");
    SET_FUNC(pHandle, ProxyDestroyDevice, dauproxy_api_func::ProxyDestroyDevice, "Proxy_S_DestroyDevice");
    SET_FUNC(pHandle, ProxySetChannelName, dauproxy_api_func::ProxySetChannelName, "Proxy_S_SetChannelName");
    SET_FUNC(pHandle, ProxyRegisterPTZCB, dauproxy_api_func::ProxyRegisterPTZCB, "Proxy_S_RegisterPTZCB");
    SET_FUNC(pHandle, ProxyRegisterRecCB, dauproxy_api_func::ProxyRegisterRecCB, "Proxy_S_RegisterRecCB");
    SET_FUNC(pHandle, ProxyModifyRecChannelInfo, dauproxy_api_func::ProxyModifyRecChannelInfo, "Proxy_S_ModifyRecChannelInfo");
    SET_FUNC(pHandle, ProxyModifyDeviceDescover, dauproxy_api_func::ProxyModifyDeviceDescover, "Proxy_S_ModifyDeviceDescover");
    SET_FUNC(pHandle, ProxyModifyDeviceInfo, dauproxy_api_func::ProxyModifyDeviceInfo, "Proxy_S_ModifyDeviceInfo");
    return 0;
}
